package com.module.reading;

import com.alibaba.fastjson.JSONObject;
import com.module.common.utils.HexUtils;
import com.module.common.utils.RedisUtils;
import com.module.common.utils.StringUtils;
import com.module.netty.channel.NettyChannel;
import com.module.netty.util.NettyUtil;
import com.module.record.service.IRecordControlService;
import com.module.record.service.IRecordOnlineService;
import com.module.record.service.IRecordReadingService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@ChannelHandler.Sharable
@Slf4j
public class NettyHandler extends ChannelInboundHandlerAdapter {

    @Autowired
    private NettyChannel nettyChannel;

    @Autowired
    private IRecordOnlineService recordOnlineService;

    @Autowired
    private IRecordControlService recordControlService;

    @Autowired
    private IRecordReadingService recordReadingService;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 活跃的、有效的通道
     * 第一次连接成功后进入的方法
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        super.channelActive(ctx);
        String channelId = ctx.channel().id().asLongText();
        String ip = NettyUtil.getRemoteAddress(ctx).getAddress().getHostAddress();
        log.info("电表服务与通道号为" + channelId + "的客户端" + ip + "建立连接，通道开启！");
        //将tcp客户端的channel信息保存
        nettyChannel.addChannel(ctx.channel());
    }

    /**
     * 不活动的通道
     * 连接丢失后执行的方法（client端可据此实现断线重连）
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        String channelId = ctx.channel().id().asLongText();
        if(redisUtils.hHasValue("device_online", channelId)) {
            String deviceImei = redisUtils.hgetValue("device_imei", channelId).toString();
            if(StringUtils.isNotEmpty(deviceImei)) {
                // 删除上线状态
                redisUtils.hdel("device_online", deviceImei);
                log.error("电表服务与通道号为" + channelId + "的客户端" + deviceImei + "失去连接，通道关闭！");

                JSONObject offlineJson = new JSONObject();
                offlineJson.put("deviceImei", deviceImei);
                offlineJson.put("remark", "设备离线");
                recordOnlineService.insertRecordOffline(offlineJson);
            }
        }
        //移除tcp客户端的channel信息
        nettyChannel.removeChannel(ctx.channel());
        //断开连接
        ctx.disconnect();
    }

    /**
     * 拿到传过来的msg数据，开始处理
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        //获取管道id
        String channelId = ctx.channel().id().asLongText();
        String ip = NettyUtil.getRemoteAddress(ctx).getAddress().getHostAddress();
        // 消息转换成字符串数组
        String[] msgs = HexUtils.strChange(msg.toString(), 2);
        if(msg.toString().startsWith("BBFF")) {
            // 获取设备imei号
            String deviceImei = HexUtils.hexStr2Str(HexUtils.strChangeStr(msgs, 2, false));
            if(deviceImei.matches("^\\d+$")) {
                // DTU注册包
                log.info("服务接收到通道号为" + channelId + "DTU客户端" + deviceImei + "的注册信息" + msg.toString());
                JSONObject onlineJson = new JSONObject();
                onlineJson.put("deviceImei", deviceImei);
                onlineJson.put("deviceType", "DTU");
                onlineJson.put("remark", "注册上线");
                recordOnlineService.insertRecordOnline(onlineJson);

                redisUtils.hset("device_online", deviceImei, channelId);
            }
        } else if(msg.toString().startsWith("BBAA")) {
            // DTU心跳包
            String deviceImei = HexUtils.hexStr2Str(HexUtils.strChangeStr(msgs, 2, false));
            //if(deviceImei.matches("^\\d+$")) {
            //    log.info("服务接收到通道号为" + channelId + "DTU客户端" + deviceImei + "的心跳信息" + msg.toString());
            //}
        } else if(msg.toString().startsWith("42424545") || msg.toString().startsWith("BBEE")) {
            // 4G电表注册包
            log.info("电表服务接收到通道号为" + channelId + "客户端" + ip + "的注册包信息" + msg.toString());
            JSONObject onlineJson = NettyUtil.parseRegister(msg.toString());
            onlineJson.put("deviceType", "4G");
            onlineJson.put("remark", "注册上线");
            recordOnlineService.insertRecordOnline(onlineJson);

            redisUtils.hset("device_online", onlineJson.getString("deviceImei"), channelId);
        } else if(redisUtils.hHasValue("device_online", channelId)) {
            String deviceImei = redisUtils.hgetValue("device_online", channelId).toString();
            if(msgs.length == 6 && !msg.toString().endsWith("4F4B0D0A")) {
                //log.info("电表服务接收到通道号为" + channelId + "客户端" + deviceImei + "的心跳包信息" + msg.toString());
                // 心跳包回复
                nettyChannel.writeToClient(channelId, "7868", "心跳回复");
            } else if(msg.toString().startsWith("B01F")) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("deviceImei", deviceImei);
                jsonObject.put("returnOrder", msg.toString());
                recordControlService.insertDeviceInfo(jsonObject);
            } else {
                if(msg.toString().endsWith("4F4B0D0A")) {
                    log.info("电表服务接收到通道号为" + channelId + "客户端" + deviceImei + "的设备控制信息" + msg.toString());
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("deviceImei", deviceImei);
                    jsonObject.put("returnOrder", msg.toString());
                    recordControlService.updateRecordControl(jsonObject);
                } else if(msg.toString().length() > 100) {
                    log.info("电表服务接收到通道号为" + channelId + "客户端" + deviceImei + "的设备定时上报信息" + msg.toString());
                    // 4G电表表端主动上报
                    if(msg.toString().endsWith("16")) {
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("deviceImei", deviceImei);
                        jsonObject.put("returnOrder", msg.toString());
                        recordReadingService.insertRecordReading(jsonObject);
                    } else {
                        redisUtils.set("data_content:" + deviceImei, msg.toString(), 5);
                    }
                } else {
                    log.info("电表服务接收到通道号为" + channelId + "客户端" + deviceImei + "的数据信息" + msg.toString());
                    if(redisUtils.hasKey("data_content:" + deviceImei)) {
                        String content = redisUtils.get("data_content:" + deviceImei);
                        content = content + msg.toString();
                        JSONObject jsonObject = new JSONObject();
                        jsonObject.put("deviceImei", deviceImei);
                        jsonObject.put("returnOrder", content);
                        recordReadingService.insertRecordReading(jsonObject);
                    }
                }
            }
        } else {
            log.error("电表服务接收到通道号为" + channelId + "客户端" + ip + "的错误数据" + msg.toString());
        }
    }

    /**
     * 心跳机制，超时处理
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        String channelId = ctx.channel().id().asLongText();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE) {
                if(redisUtils.hHasValue("device_online", channelId)) {
                    String deviceImei = redisUtils.hgetValue("device_online", channelId).toString();
                    if(StringUtils.isNotEmpty(deviceImei)) {
                        // 删除上线状态
                        redisUtils.hdel("device_online", deviceImei);
                        log.error("务与通道号为" + channelId + "的客户端" + deviceImei + "失去连接，通道关闭！");

                        JSONObject offlineJson = new JSONObject();
                        offlineJson.put("deviceImei", deviceImei);
                        offlineJson.put("remark", "设备超时离线");
                        recordOnlineService.insertRecordOffline(offlineJson);
                    }
                }
                // 移除tcp客户端的channel信息
                nettyChannel.removeChannel(ctx.channel());
                // 断开连接
                ctx.disconnect();
            } else if (event.state() == IdleState.WRITER_IDLE) {
                log.error("通道号为" + channelId + "的客户端写超时");
                ctx.disconnect();
            } else if (event.state() == IdleState.ALL_IDLE) {
                log.error("通道号为" + channelId + "的客户端超时");
                ctx.disconnect();
            }
        }
    }
}
